﻿using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Threading;
using System.Windows.Forms;
using Slippor.Douban.Radio.Assist;
using Slippor.Douban.Radio.BaseForm.Properties;
using Timer = System.Windows.Forms.Timer;
using System.Text.RegularExpressions;

namespace Slippor.Douban.Radio.BaseForm
{
    public partial class DoubanForm
    {
        private SHDocVw.WebBrowser _axBrowser;
        protected virtual void InitialControls()
        {
            RadioUtility.MuteNavigation();
            webBrowserDouban.DocumentTitleChanged += WbDoubanDocumentTitleChanged;
            webBrowserDouban.Navigated += webBrowserDouban_Navigated;
            webBrowserDouban.DocumentCompleted += webBrowserDouban_DocumentCompleted;
            webBrowserDouban.PreviewKeyDown += (sender, e) =>
                {
                    if(e.KeyCode == Keys.F5)
                    {
                        webBrowserDouban.Navigate(StaticResources.RadioUrl);
                    }
                };

            _axBrowser = (SHDocVw.WebBrowser)webBrowserDouban.ActiveXInstance;
            _axBrowser.Silent = true;
            _axBrowser.BeforeNavigate2 += _axBrowser_BeforeNavigate2;
            _axBrowser.NewWindow3 += axBrowser_NewWindow3;
            menuStripTop.MenuActivate += (sender, e) =>
                {
                    _menuStripTopOpened = true;
                };
            menuStripTop.MenuDeactivate += (sender, e) =>
                {
                    _menuStripTopOpened = false;
                };
            InitialColors();
            InitialContextMenu();
            InitialDock();
            InitialBottomMenu();
            toolStripMenuItemSearch.MainApplication = this;
        }

        #region 按钮样式
        private void InitialColors()
        {
            Color imageBackColor = Color.FromArgb(201, 201, 201);
            pictureBoxMenu.BackColor = imageBackColor;
        }
        #endregion

        #region 快捷菜单
        private readonly LinkLabel _favLabel = new LinkLabel
                                                   {
                Text = @"加心 ... 首",
                TextAlign = ContentAlignment.BottomCenter,
                ForeColor = Color.Gray,
                LinkColor = Color.Black,
            };
        private readonly LinkLabel _totalLabel = new LinkLabel
                                                     {
            Text = @"累积收听 ... 首",
            TextAlign = ContentAlignment.BottomCenter,
            ForeColor = Color.Gray,
            LinkColor = Color.Black,
        };
        private readonly LinkLabel _delLabel = new LinkLabel
                                                   {
            Text = @"... 首不再播放",
            TextAlign = ContentAlignment.BottomCenter,
            ForeColor = Color.Gray,
            LinkColor = Color.Black,
        };

        private void InitialBottomMenu()
        {
            _favLabel.Click += (e, a) => { RadioUtility.Browse("http://douban.fm/mine?type=liked"); };
            _totalLabel.Click += (e, a) => { RadioUtility.Browse("http://douban.fm/mine?type=played"); };
            _delLabel.Click += (e, a) => { RadioUtility.Browse("http://douban.fm/mine?type=banned"); };
            var fav = new ToolStripControlHost(_favLabel) { Margin = new Padding(10, 0, 5, 0) };
            var total = new ToolStripControlHost(_totalLabel) { Margin = new Padding(5, 0, 5, 0) };
            var del = new ToolStripControlHost(_delLabel) { Margin = new Padding(5, 0, 5, 0) };
            toolStripBottom.Items.Add(fav);
            toolStripBottom.Items.Add(total);
            toolStripBottom.Items.Add(del);
        }

        private int _addtionHeight = 0;
        private void pictureBoxMenu_Click(object sender, EventArgs e)
        {
            MenuOpen = !MenuOpen;
            ShowTopMenu(MenuOpen);
        }

        public void ShowTopMenu(bool show)
        {
            toolStripContainer.TopToolStripPanelVisible = show;
            menuStripTop.Visible = show;
            if (show)
            {
                if (_addtionHeight == 0)
                {
                    _addtionHeight = menuStripTop.Height;
                    this.Height += _addtionHeight;
                    OnHeightChanged(_addtionHeight);
                }
            }
            else
            {
                if (_addtionHeight != 0)
                {
                    _addtionHeight = 0;
                    this.Height -= menuStripTop.Height;
                    OnHeightChanged(-menuStripTop.Height);
                }
            }
        }

        protected virtual void OnHeightChanged(int height)
        {
        }

        private void loginToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ConfirmLogin();
        }

        private void configToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ShowConfig();
        }
 
        private void pictureBoxMenuBottom_Click(object sender, EventArgs e)
        {
            BottomMenuOpen = !BottomMenuOpen;
            ShowBottomMenu(BottomMenuOpen);
        }

        public void ShowBottomMenu(bool show)
        {
            toolStripBottom.Visible = show;
        }
        #endregion

        #region 浏览器事件
        bool _isFakeClick;
        private void axBrowser_NewWindow3(ref object ppDisp, ref bool Cancel, uint dwFlags, string bstrUrlContext, string bstrUrl)
        {
            if (_isFakeClick)
            {
                _isFakeClick = false;
                using (var infoBackgroundWorker = new BackgroundWorker())
                {
                    infoBackgroundWorker.DoWork += (sender, e) => e.Result = SetInfo(e.Argument);
                    infoBackgroundWorker.RunWorkerCompleted += (sender, e) =>
                        {
                            var song = e.Result as Song;
                            if (song != null)
                            {
                                if (song == _currentSong)
                                {
                                    if (song.Album != null)
                                    {
                                        SetInfoToolStripItem(true);
                                        SetTitles(String.Format("{0} - {1}", song.Title, song.Album.ArtistString));
                                        String titleWithMark = String.Format("{0} - {1} ({2})", song.Title, song.Album.ArtistString, song.Album.Mark);
                                        toolStripMenuItemSearch.SearchSong = _currentSong;
                                        if (titleWithMark.Length > _textTitleLength)
                                        {
                                            titleWithMark = titleWithMark.Substring(0, _textTitleLength);
                                        }
                                        Text = titleWithMark;
                                        notifyIcon.Text = titleWithMark;
                                    }
                                    else
                                    {
                                        SetInfoToolStripItem(false);
                                        if(!String.IsNullOrEmpty(song.SongID))
                                        {
                                            _getSongInfo = true;
                                        }
                                    }
                                }
                                if (song.Album != null)
                                {
                                    TrackUpdate(CommandFactory.GetCommand(Command.Other, _currentType), song);
                                }
                            }
                        };
                    infoBackgroundWorker.RunWorkerAsync(bstrUrl);
                }
            }
            else
            {
                RadioUtility.Browse(bstrUrl);
                RadioUtility.ReleaseMemory();
            }
            Cancel = true;
        }

        private void _axBrowser_BeforeNavigate2(object pDisp, ref object URL, ref object Flags, ref object TargetFrameName, ref object PostData, ref object Headers, ref bool Cancel)
        {
            ShowLoading();
            if (URL.ToString().ToLower() == "http://www.douban.com/login")
            {
            }
        }

        private void webBrowserDouban_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
        {
            loginToolStripMenuItem.Text = StringResource.Loggin;
            if (e.Url.AbsoluteUri.IndexOf(StaticResources.RadioUrl) == 0)
            {
                if (!webBrowserDouban.IsBusy &&  webBrowserDouban.ReadyState == WebBrowserReadyState.Complete && webBrowserDouban.Document != null)
                {
                    if (webBrowserDouban.Document.Window != null)
                    {
                        webBrowserDouban.Document.Window.ScrollTo(440, 160);
                    }
                    var cookie = new DoubanCookie { CookieString = webBrowserDouban.Document.Cookie };
                    lock (_currentAccount)
                    {
                        String doc = webBrowserDouban.DocumentText;
                        DoubanAccount account = AccountControl.GetAccount(doc, cookie);
                        if (account.IsLoged)
                        {
                            if (_currentAccount.Name != account.Name)
                            {
                                _currentAccount.Name = account.Name;
                            }
                            GetListenInfo(doc);
                            SetListenInfo();
                        }
                        _currentAccount.Cookie = account.Cookie;
                        _currentAccount.LogState = LogState.Idle;
                        SetAccountInfo();
                    }
                }
                OnRadioLoaded();
            }
            else
            {
                loginToolStripMenuItem.Enabled = false;
            }
        }

        private const String _listenInfoPattern =  "<em id=\"liked\" class=\"n\"><span class=\"v\">(?<like>\\d+)"+
      "[\\w\\W]*?<em id=\"total\" class=\"n\"><span class=\"v\">(?<"+
      "total>\\d+)[\\w\\W]*?<em id=\"banned\" class=\"n\"><span cla"+
      "ss=\"v\">(?<ban>\\d+)";
        private int _like = 0;
        private int _total = 0;
        private int _ban = 0;
        /// <summary>
        /// 设置听歌历史。
        /// </summary>
        private void GetListenInfo(String doc)
        {
            Match match = Regex.Match(doc,_listenInfoPattern);
            if (match.Success)
            {
                Int32.TryParse(match.Groups["like"].Value,out _like);
                Int32.TryParse(match.Groups["total"].Value, out _total);
                Int32.TryParse(match.Groups["ban"].Value, out _ban);
            }
        }

        private void SetListenInfo()
        {
            _favLabel.Text = String.Format("加心 {0:N0} 首", _like);
            _totalLabel.Text = String.Format("累积收听 {0:N0} 首", _total);
            _delLabel.Text = String.Format("{0:N0} 首不再播放", _ban);
        }

        protected virtual void OnRadioLoaded()
        {
            ;
        }


        private void webBrowserDouban_Navigated(object sender, WebBrowserNavigatedEventArgs e)
        {
            HideLoading();
            if (e.Url.AbsolutePath == "/logout")
            {
                webBrowserDouban.Navigate(StaticResources.LoginUrl);
            }
        }

        private void WbDoubanDocumentTitleChanged(object sender, EventArgs e)
        {
            Drop(_currentSong);
            _currentSong = new Song { Title = webBrowserDouban.DocumentTitle };
            if (_normalFilter.Filter(ref _currentSong))
            {
                if (_isPlaying)
                {
                    OnExecute(Command.Control);
                }
                if (_currentSong.Title.IndexOf(Song.DefaultTitle) == -1)
                {
                    if (_currentState == RadioState.Notify)
                    {
                        _currentState = RadioState.Normal;
                        ShowFromNotify();
                    }
                }
            }
            else
            {
                if (!_isPlaying)
                {
                    OnExecute(Command.Control);
                }
                _total++;
                SetListenInfo();
                toolStripMenuItemSearch.KeyWord = _currentSong.Title;
                TrackHistory(_currentSong);
                FreshInfo(0.75, (ref Song song) =>
                              {
                                  if (_currentSong == song)
                                  {
                                      if (!Filter())
                                      {
                                          PopInfo(_currentSong.Title);
                                          Hand(_currentSong);
                                          if (GetInfo)
                                          {
                                              _getSongInfo = true;
                                          }
                                          else
                                          {
                                              toolStripMenuItemGetInfo.Text = StringResource.SongInfo_UnGot;
                                              toolStripMenuItemGetInfo.ToolTipText = Resources.DoubanForm_GetSongInfo_FailedToolTip;
                                              toolStripMenuItemGetInfo.Enabled = true;
                                          }
                                      }
                                  }
                              });
            }
            SetTitles(_currentSong.Title);
            RadioUtility.ReleaseMemory();
        }

        private Timer _loadingTimer;
        private readonly String _loadingString = StringResource.Loading;
        private void ShowLoading()
        {
            labelLoading.Visible = true;
            lock(_forLock)
            {
                if (_loadingTimer != null)
                {
                    _loadingTimer.Stop();
                    _loadingTimer = null;
                }
                _loadingTimer = new Timer { Interval = 500 };
                _loadingTimer.Tick += (sender, e) =>
                    {
                        if (labelLoading.Text.Length == 0 || labelLoading.Text.Length > 9)
                        {
                            labelLoading.Text = _loadingString;
                        }
                        else
                        {
                            labelLoading.Text = labelLoading.Text + ".";
                        }
                    };
                _loadingTimer.Start();
            }
        }

        private void HideLoading()
        {
            labelLoading.Visible = false;
            labelLoading.Text = String.Empty;
            lock (_forLock)
            {
                if (_loadingTimer != null)
                {
                    _loadingTimer.Stop();
                    _loadingTimer = null;
                }
            }
        }
        #endregion

        #region 获取歌曲信息
        private const int _toolTipTitleLength = 18;
        private const int _textTitleLength = 63;
        private void SetTitles(String title)
        {
            SuspendLayout();
            if (title.Length > _toolTipTitleLength)
            {
                toolStripMenuItemTitle.Text = title.Substring(0, _toolTipTitleLength) + @"...";
            }
            else
            {
                toolStripMenuItemTitle.Text = title;
            }
            toolStripMenuItemTitle.ToolTipText = title;
            if (title.Length > _textTitleLength)
            {
                title = title.Substring(0, _textTitleLength);
            }
            Text = title;
            notifyIcon.Text = title;
            SetDockLabel(title);
            ResumeLayout();
        }

        private bool _getSongInfo = false;
        /// <summary>
        /// 在空闲时获取歌曲信息，提高获取成功率。
        /// </summary>
        private void GetSongInfo()
        {
            toolStripMenuItemGetInfo.Text = Resources.DoubanForm_GetSongInfo_InfoGeting;
            toolStripMenuItemGetInfo.Enabled = false;
            using(var getInfoBackgroundWorker = new BackgroundWorker())
            {
                getInfoBackgroundWorker.DoWork += (sender, e) =>
                {
                    int tryTime = 1;
                    const int sleepTime = 2500;
                    Song song = e.Argument as Song;
                    _isFakeClick = true;
                    while (tryTime > 0 && _isFakeClick && song == _currentSong && _isPlaying)
                    {
                        if (!DropdownOpen)
                        {
                            ExcuteCommand(new FakeClickCommand(100, 100));
                        }
                        tryTime--;
                        Thread.Sleep(sleepTime);
                    }
                    e.Result = song;
                };
                getInfoBackgroundWorker.RunWorkerCompleted += (sender, e) =>
                {
                    Song song = e.Result as Song;
                    if (_isPlaying && song == _currentSong)
                    {
                        if (_isFakeClick)
                        {
                            _isFakeClick = false;
                            SetInfoToolStripItem(false);
                            _getSongInfo = true;
                        }
                    }
                };
                getInfoBackgroundWorker.RunWorkerAsync(_currentSong);
            }
        }

        private Song SetInfo(object bstrUrl)
        {
            Song song = _currentSong;
            Song.SetInfo(bstrUrl.ToString(), song);
            RadioUtility.ReleaseMemory();
            return song;
        }

        private void SetInfoToolStripItem(bool succeed)
        {
            if (succeed)
            {
                toolStripMenuItemGetInfo.Text = Resources.DoubanForm_GetSongInfo_Succeed;
                toolStripMenuItemGetInfo.Enabled = false;
                toolStripMenuItemGetInfo.ToolTipText = String.Empty;
            }
            else
            {
                toolStripMenuItemGetInfo.Text = Resources.DoubanForm_GetSongInfo_Failed;
                toolStripMenuItemGetInfo.Enabled = true;
                toolStripMenuItemGetInfo.ToolTipText = Resources.DoubanForm_GetSongInfo_FailedToolTip;
            }
        }
        #endregion

        #region 歌曲处理
        private void Hand(Song song)
        {
            using (var handlerWorker = new BackgroundWorker())
            {
                handlerWorker.DoWork += (sender, e) =>
                                            {
                                                _handlerService.Hand(song);
                                                RadioUtility.ReleaseMemory();
                                            };
                handlerWorker.RunWorkerAsync();
            }
        }

        private void Drop(Song song)
        {
            using (var handlerWorker = new BackgroundWorker())
            {
                handlerWorker.DoWork += (sender, e) =>
                                            {
                                                _handlerService.Drop(song);
                                                RadioUtility.ReleaseMemory();
                                            };
                handlerWorker.RunWorkerAsync();
            }
        }

        internal bool Filter()
        {
            bool isFilter = _filters.Filter(ref _currentSong);
            if (isFilter)
            {
                ExcuteCommand(CommandFactory.GetCommand(Command.Filter, _currentType));
            }
            return isFilter;
        }
        #endregion

        #region 歌曲操作
        public void PopInfo()
        {
            if (_currentSong != null)
            {
                PopInfo(_currentSong);
            }
        }

        public void PopInfo(Song song)
        {
            String message = song.Title;
            if (song.Album != null)
            {
                message = String.Format("{0}-{1}", song.Title, song.Album.ArtistString);
            }
            notifyIcon.ShowBalloonTip(1000, StringResource.Title, message, ToolTipIcon.Info);
        }

        public void PopInfo(String message)
        {
            if (NotifyPop)
            {
                notifyIcon.ShowBalloonTip(1000, StringResource.Title, message, ToolTipIcon.Info);
            }
        }

        private void CopyInfo(String info)
        {
            int tryTime = 3;
            while (tryTime > 0)
            {
                try
                {
                    Clipboard.SetText(info);
                    PopInfo(StringResource.Copied);
                    tryTime = 0;
                }
                catch (Exception)
                {
                    tryTime--;
                }
            }
        }

        private void FreshInfo(double second, params PostFresh[] postFreshs)
        {
            var timer = new Timer { Interval = (int)(second * 1000) };
            timer.Tick += (sender, e) =>
            {
                timer.Stop();
                ConfirmHandler();
                IntPtr hdc = RadioUtility.GetDC(_wbHandle); //对本窗体获取
                SetType(hdc);
                SetFav(hdc);
                RadioUtility.ReleaseDC(_wbHandle, hdc);
                if (postFreshs != null)
                {
                    foreach (PostFresh postFresh in postFreshs)
                    {
                        postFresh(ref _currentSong);
                    }
                }
                timer.Dispose();
                timer = null;
                RadioUtility.ReleaseMemory();
            };
            timer.Start();
        }

        private void SetType(IntPtr hdc)
        {
            //RadioType radioType = CheckType(hdc);
            RadioType radioType = RadioType.PrivateRadio;
            if (radioType != RadioType.Unknown)
            {
                _currentType = radioType;
            }
            OnSetType(_currentType);
        }

        private void SetFav(IntPtr hdc)
        {
            _currentSong.FaveState = CheckFav(hdc);
            OnSetFav(_currentSong);
        }

        protected virtual void OnSetType(RadioType currentType)
        {
            switch (currentType)
            {
                case RadioType.PrivateRadio:
                    toolStripMenuItemDel.Enabled = _isPlaying;
                    break;
                case RadioType.PublicRadio:
                    toolStripMenuItemDel.Enabled = false;
                    break;
                case RadioType.Unknown:
                    toolStripMenuItemDel.Enabled = _isPlaying;
                    break;
            }
        }

        protected virtual void OnSetFav(Song song)
        {
            switch (song.FaveState)
            {
                case FavState.Unknown:
                    toolStripMenuItemFav.Text = StringResource.Command_LikeUnlike;
                    break;
                case FavState.Fav:
                    toolStripMenuItemFav.Text = StringResource.Command_Unlike;
                    TrackUpdate(CommandFactory.GetCommand(Command.Fav, RadioType.PrivateRadio));
                    dockPanel.IconImage = ImageCache.Fav;
                    break;
                case FavState.UnFav:
                    toolStripMenuItemFav.Text = StringResource.Command_Like;
                    TrackUpdate(CommandFactory.GetCommand(Command.Fav, RadioType.PrivateRadio));
                    dockPanel.IconImage = ImageCache.UnFav;
                    break;
            }
        }

        private Song _targetSong;
        protected void ExcuteCommand(ICommand command)
        {
            _targetSong = _currentSong;
            ConfirmHandler();
            RadioUtility.ControlFlash(_wbHandle, command.X, command.Y);
            OnExecute(command.Command);
        }

        protected virtual void OnExecute(Command command)
        {
            switch (command)
            {
                case Command.Control:
                    _isPlaying = !_isPlaying;
                    toolStripMenuItemDel.Enabled = _isPlaying && (_currentType != RadioType.PublicRadio);
                    toolStripMenuItemFav.Enabled = _isPlaying;
                    toolStripMenuItemNext.Enabled = _isPlaying;
                    if (!_isPlaying)
                    {
                        toolStripMenuItemControl.Text = StringResource.Command_Play;
                        PopInfo(StringResource.Command_Stop);
                        TrackPause();
                    }
                    else
                    {
                        toolStripMenuItemControl.Text = StringResource.Command_Stop;
                        PopInfo(StringResource.Command_Play);
                        TrackResume();
                    }
                    break;
                case Command.Fav:
                case Command.UnFav:
                    FavState currentFavState = _currentSong.FaveState;
                    FreshInfo(0.15, (ref Song song) =>
                    {
                        if (_currentSong == song && _currentSong.FaveState != currentFavState)
                        {
                            if (song.FaveState == FavState.Fav)
                            {
                                PopInfo(StringResource.Command_Like);
                            }
                            else
                            {
                                PopInfo(StringResource.Command_Unlike);
                            }
                        }
                    });
                    break;
                default:
                    FreshInfo(0.5, (ref Song song) =>
                    {
                        if (_targetSong != _currentSong)
                        {
                            TrackUpdate(CommandFactory.GetCommand(command, RadioType.PrivateRadio));
                        }
                    });

                    break;
            }
            _targetSong = null;
        }
        #endregion

        #region 当前用户
        private readonly DoubanAccount _currentAccount = DoubanAccount.UnLogedAccount;
        internal DoubanAccount CurrentAccount
        {
            get { return _currentAccount; }
        }

        private readonly LoginForm _loginForm = new LoginForm();
        private bool ConfirmLogin()
        {
            if (!_currentAccount.IsLoged)
            {
                Login();
            }
            else
            {
                switch (_loginForm.ShowDialog())
                {
                    case DialogResult.OK:
                        Login();
                        break;
                    case DialogResult.Yes:
                        TotallyLogin();
                        break;
                    default:
                        return false;
                }
            }
            return true;
        }

        private void Login()
        {
            webBrowserDouban.Navigate(StaticResources.LoginUrl);
        }

        private void TotallyLogin()
        {
            if (_currentAccount.CurrentSession != null)
            {
                webBrowserDouban.Navigate(String.Format("http://www.douban.com/logout?ck={0}", _currentAccount.CurrentSession.Replace("\"", "")));
            }
            else
            {
                Login();
            }
        }

        internal  void SetCookie()
        {
            RadioUtility.InternetSetCookie(StaticResources.RadioUrl, DoubanAccount.SessionKey, _currentAccount.CurrentSession);
            RadioUtility.InternetSetCookie(StaticResources.RadioUrl, DoubanAccount.IDKey, _currentAccount.ID);
        }

        private void SetAccountInfo()
        {
            if (_currentAccount.LogState == LogState.Idle)
            {
                if (_currentAccount.IsLoged)
                {
                    Trace.WriteLine(_currentAccount.Name);
                    loginToolStripMenuItem.Text = _currentAccount.Name;
                    if (_currentAccount.IsLoginWithID)
                    {
                        loginToolStripMenuItem.ToolTipText = _currentAccount.Name;
                    }
                    else
                    {
                        loginToolStripMenuItem.ToolTipText = String.Format("*{0}", _currentAccount.Name);
                    }
                    loginToolStripMenuItem.Enabled = true;
                }
                else
                {
                    loginToolStripMenuItem.Text = Resources.DoubanForm_GetAccountInfo_UnLogin;
                    loginToolStripMenuItem.ToolTipText = StringResource.AccountInfo_ClickToLogin;
                    loginToolStripMenuItem.Enabled = true;
                }
            }
        }
        #endregion

        #region 记录历史
        private void AppendHistoryItem(ToolStripMenuItem historyItem)
        {
            if (!toolStripMenuItemHistory.DropDownItems.Contains(historyItem))
            {
                historyItem.Click += historyItem_Click;
                toolStripMenuItemHistory.DropDownItems.Insert(2, historyItem);
            }
        }

        private void historyItem_Click(object sender, EventArgs e)
        {
            var toolStripMenuItem = sender as ToolStripMenuItem;
            if (toolStripMenuItem != null)
            {
                var song = (Song) toolStripMenuItem.Tag;
                CopyInfo(song.Title);
                toolStripMenuItemSearch.SearchSong = song;
                contextMenuStripNotify.Show();
                toolStripMenuItemSearch.ShowDropDown();
            }
        }
        #endregion

    }

    public delegate void PostFresh(ref Song song);
    public delegate void Pause();
}